package com.tgb.lk.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.*;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import com.tgb.lk.config.Config;
import com.tgb.lk.config.ConfigXmlUtil;
import com.tgb.lk.table.Log;
import com.tgb.lk.table.TableConfig;

public class FileUtil {
	public FileUtil() {
	}

	/**
	 * 新建目录
	 * 
	 * @param folderPath
	 *            String 如 c:/fqf
	 * @return boolean
	 */
	public static void newFolder(String folderPath) {
		folderPath = filterDir(folderPath);
		try {
			String filePath = folderPath;
			filePath = filePath.toString();
			java.io.File myFilePath = new java.io.File(filePath);
			if (!myFilePath.exists()) {
				boolean dirFlag = myFilePath.mkdir();
			}
		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();
		}
	}

	/**
	 * 新建文件
	 * 
	 * @param filePathAndName
	 *            String 文件路径及名称 如c:/fqf.txt
	 * @param fileContent
	 *            String 文件内容
	 * @return boolean
	 */
	public static void newFile(String filePathAndName, String fileContent) {

		try {
			String filePath = filePathAndName;
			filePath = filePath.toString();
			File myFilePath = new File(filePath);
			if (!myFilePath.exists()) {
				boolean dirFlag = myFilePath.createNewFile();
			}
			FileWriter resultFile = new FileWriter(myFilePath);
			PrintWriter myFile = new PrintWriter(resultFile);
			String strContent = fileContent;
			myFile.println(strContent);
			myFile.close();
			resultFile.close();
		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();

		}

	}

	/**
	 * 删除文件
	 * 
	 * @param filePathAndName
	 *            String 文件路径及名称 如c:/fqf.txt
	 * @param fileContent
	 *            String
	 * @return boolean
	 */
	public static void delFile(String filePathAndName) {
		try {
			String filePath = filePathAndName;
			filePath = filePath.toString();
			java.io.File myDelFile = new java.io.File(filePath);
			boolean dirFlag = myDelFile.delete();

		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();

		}

	}

	/**
	 * 删除文件夹
	 * 
	 * @param filePathAndName
	 *            String 文件夹路径及名称 如c:/fqf
	 * @param fileContent
	 *            String
	 * @return boolean
	 */
	public static void delFolder(String folderPath) {
		folderPath = filterDir(folderPath);
		try {
			delAllFile(folderPath); // 删除完里面所有内容
			String filePath = folderPath;
			filePath = filePath.toString();
			java.io.File myFilePath = new java.io.File(filePath);
			boolean dirFlag = myFilePath.delete(); // 删除空文件夹

		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();

		}

	}

	/**
	 * 删除文件夹里面的所有文件
	 * 
	 * @param path
	 *            String 文件夹路径 如 c:/fqf
	 */
	public static void delAllFile(String path) {
		path = filterDir(path);
		File file = new File(path);
		if (!file.exists()) {
			return;
		}
		if (!file.isDirectory()) {
			return;
		}
		String[] tempList = file.list();
		File temp = null;
		for (int i = 0; i < tempList.length; i++) {
			if (path.endsWith(File.separator)) {
				temp = new File(path + tempList[i]);
			} else {
				temp = new File(path + File.separator + tempList[i]);
			}
			if (temp.isFile()) {
				boolean dirFlag = temp.delete();
			}
			if (temp.isDirectory()) {
				delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
				delFolder(path + "/" + tempList[i]);// 再删除空文件夹
			}
		}
	}

	/**
	 * 复制单个文件
	 * 
	 * @param oldPath
	 *            String 原文件路径 如：c:/fqf.txt
	 * @param newPath
	 *            String 复制后路径 如：f:/fqf.txt
	 * @return boolean
	 */
	public static void copyFile(String oldPath, String newPath) {
		oldPath = filterDir(oldPath);
		newPath = filterDir(newPath);
		if (oldPath.toLowerCase().equals(newPath.toLowerCase())) {
			return;
		}
		try {
			int bytesum = 0;
			int byteread = 0;
			File oldfile = new File(oldPath);
			if (oldfile.exists()) { // 文件存在时
				InputStream inStream = new FileInputStream(oldPath); // 读入原文件
				makeFilePath(newPath);
				FileOutputStream fs = new FileOutputStream(newPath);
				byte[] buffer = new byte[1444];
				while ((byteread = inStream.read(buffer)) != -1) {
					bytesum += byteread; // 字节数 文件大小
					fs.write(buffer, 0, byteread);
				}
				fs.flush();
				fs.close();
				inStream.close();
			}
		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();

		}

	}

	/**
	 * 复制单个文件
	 * 
	 * @param oldPath
	 *            String 原文件路径 如：c:/fqf.txt
	 * @param newPath
	 *            String 复制后路径 如：f:/fqf.txt
	 * @return boolean
	 */
	public static void copyFile(InputStream inStream, String newPath) {
		newPath = filterDir(newPath);
		try {
			int bytesum = 0;
			int byteread = 0;
			FileOutputStream fs = new FileOutputStream(filterDir(newPath));
			byte[] buffer = new byte[1444];
			while ((byteread = inStream.read(buffer)) != -1) {
				bytesum += byteread; // 字节数 文件大小
				fs.write(buffer, 0, byteread);
			}
			fs.flush();
			fs.close();
			inStream.close();
		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();

		}

	}

	public static List<String> getAllFiles(String path, List<String> retList) {
		path = filterDir(path);
		if (retList == null) {
			retList = new ArrayList<String>();
		}
		File a = new File(path);
		String[] file = a.list();
		File temp = null;
		if (file == null || file.length == 0) {
			return retList;
		}
		for (int i = 0; i < file.length; i++) {
			if (path.endsWith(File.separator)) {
				temp = new File(path + file[i]);
			} else {
				temp = new File(path + File.separator + file[i]);
			}

			if (temp.isFile()) {
				retList.add(temp.getAbsolutePath());
			} else if (temp.isDirectory() && !temp.getName().endsWith(".svn")) {// 如果是子文件夹
				getAllFiles(path + File.separator + file[i], retList);
			}
		}

		return retList;
	}

	public static void copyFileByLines(String oldPath, String newPath,
			String[] filterString) {
		oldPath = filterDir(oldPath);
		newPath = filterDir(newPath);
		if (oldPath.toLowerCase().equals(newPath.toLowerCase())) {
			return;
		}
		if (oldPath.toLowerCase().equals(newPath.toLowerCase())) {
			return;
		}
		boolean dirFlag = (new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹
		File a = new File(oldPath);
		String[] file = a.list();
		File temp = null;
		if (file == null || file.length == 0) {
			return;
		}
		for (int i = 0; i < file.length; i++) {
			if (oldPath.endsWith(File.separator)) {
				temp = new File(oldPath + file[i]);
			} else {
				temp = new File(oldPath + File.separator + file[i]);
			}

			if (temp.isFile() && temp.getName().endsWith(".java")) {

				BufferedReader reader = null;
				try {
					// System.out.println("以行为单位读取文件内容，一次读一整行：");
					reader = new BufferedReader(new FileReader(temp));
					FileWriter writer = new FileWriter(filterDir(newPath + "/"
							+ (temp.getName()).toString()));
					String tempString = null;
					int line = 1;
					// 一次读入一行，直到读入null为文件结束
					while ((tempString = reader.readLine()) != null) {
						// System.out.println("line " + line + ": " +
						// tempString);
						boolean flag = false;
						for (String string : filterString) {
							if (tempString.contains(string)) {
								flag = true;
								break;
							}
						}
						if (!flag) {
							writer.write(tempString + "\r\n");
						}
						line++;
					}
					writer.flush();
					writer.close();
					reader.close();
				} catch (IOException e) {
					Log.log(e);
					e.printStackTrace();
				} finally {
					if (reader != null) {
						try {
							reader.close();
						} catch (IOException e1) {
							Log.log(e1);
						}
					}
				}
			} else if (temp.isDirectory() && !temp.getName().endsWith(".svn")) {// 如果是子文件夹
				copyFileByLines(oldPath + File.separator + file[i], newPath
						+ File.separator + file[i], filterString);
			}
		}
	}

	/**
	 * 复制整个文件夹内容
	 * 
	 * @param oldPath
	 *            String 原文件路径 如：c:/fqf
	 * @param newPath
	 *            String 复制后路径 如：f:/fqf/ff
	 * @return boolean
	 */
	public static void copyFolder(String oldPath, String newPath) {
		oldPath = filterDir(oldPath);
		newPath = filterDir(newPath);
		if (oldPath.toLowerCase().equals(newPath.toLowerCase())) {
			return;
		}
		try {
			boolean dirFlag = (new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹
			File a = new File(oldPath);
			String[] file = a.list();
			if (file == null || file.length < 1) {
				return;
			}
			File temp = null;
			for (int i = 0; i < file.length; i++) {
				if (oldPath.endsWith(File.separator)) {
					temp = new File(oldPath + file[i]);
				} else {
					temp = new File(oldPath + File.separator + file[i]);
				}

				if (temp.isFile()) {
					FileInputStream input = new FileInputStream(temp);
					FileOutputStream output = new FileOutputStream(newPath
							+ File.separator + (temp.getName()).toString());
					byte[] b = new byte[1024 * 5];
					int len;
					while ((len = input.read(b)) != -1) {
						output.write(b, 0, len);
					}
					output.flush();
					output.close();
					input.close();
				}
				if (temp.isDirectory() && !temp.getName().endsWith(".svn")) {// 如果是子文件夹
					copyFolder(oldPath + File.separator + file[i], newPath
							+ File.separator + file[i]);
				}
			}
		} catch (IOException e) {
			Log.log(e);
			e.printStackTrace();

		}

	}

	public static String filterDir(String dirPath) {
		String path = dirPath.replace("/", File.separator).replace("\\",
				File.separator);
		return path.endsWith(File.separator) ? path.substring(0,
				path.length() - 1) : path;
	}

	/**
	 * 移动文件到指定目录
	 * 
	 * @param oldPath
	 *            String 如：c:/fqf.txt
	 * @param newPath
	 *            String 如：d:/fqf.txt
	 */
	public static void moveFile(String oldPath, String newPath) {
		if (filterDir(oldPath).equals(filterDir(newPath))) {
			return;
		}
		copyFile(oldPath, newPath);
		delFile(oldPath);

	}

	/**
	 * 移动文件到指定目录
	 * 
	 * @param oldPath
	 *            String 如：c:/fqf.txt
	 * @param newPath
	 *            String 如：d:/fqf.txt
	 */
	public static void moveFolder(String oldPath, String newPath) {
		copyFolder(oldPath, newPath);
		delFolder(oldPath);

	}

	public static void main(String[] args) {
		// FileUtil.newFile("test.txt", "fdsfdsfdsfs");
		// System.out.println(FileUtil.getClassfromJava(
		// "D:\\mysrc\\src\\com\\tgb\\lk\\model", null));

		List<String> files = getAllFiles(AppConstants.HELP_PATH, null);
		for (String file : files) {
			System.out.println(file.replace(AppConstants.BASE_PATH, "resources/")
					.replace("\\", "/"));
		}
	}

	public static Set<Class<?>> getClassfromJava(String path,
			Set<Class<?>> classes) {
		path = filterDir(path);
		if (classes == null) {
			classes = new LinkedHashSet<Class<?>>();
		}
		File a = new File(path);
		String[] file = a.list();
		File temp = null;
		if (file == null || file.length == 0) {
			return classes;
		}
		for (int i = 0; i < file.length; i++) {
			if (path.endsWith(File.separator)) {
				temp = new File(path + file[i]);
			} else {
				temp = new File(path + File.separator + file[i]);
			}

			if (temp.isFile() && temp.getName().endsWith(".java")) {
				String packageName = "";
				BufferedReader reader = null;
				try {
					// System.out.println("以行为单位读取文件内容，一次读一整行：");
					reader = new BufferedReader(new FileReader(temp));
					String tempString = null;
					int line = 1;
					// 一次读入一行，直到读入null为文件结束
					while ((tempString = reader.readLine()) != null) {
						if (tempString.contains("package ")) {
							packageName = tempString.replace("package ", "")
									.replace(";", "");
						}
						line++;
					}
					reader.close();
					compiler(temp.getAbsolutePath());
					String className = temp.getName().substring(0,
							temp.getName().length() - 5);

					ConfigXmlUtil util = new ConfigXmlUtil();
					Config config = util.getConfig();
					String destPath = filterDir(config.getBeansDir());
					if (!destPath.endsWith(File.separator)) {
						destPath += File.separator;
					}

					destPath = destPath
							+ packageName.replace(".", File.separator);
					// FileUtil.copyFile(temp.getAbsolutePath(),
					// makeFilePath(destPath + File.separator + className
					// + ".java"));
					FileUtil.copyFile(temp.getAbsolutePath().replace(".java",
							".class"), destPath + File.separator + className
							+ ".class");
					// try {
					// // 添加到集合中去
					// // classes.add(Class.forName(packageName + '.' +
					// // className));
					// // 这里用forName有一些不好，会触发static方法，没有使用classLoader的load干净
					// classes.add(Thread.currentThread()
					// .getContextClassLoader().loadClass(
					// packageName + '.' + className));
					// } catch (ClassNotFoundException e) {
					// Log.log(e.getMessage(), 1);
					// }
				} catch (IOException e) {
					Log.log(e);
				}
			} else if (temp.isDirectory() && !temp.getName().endsWith(".svn")) {// 如果是子文件夹
				getClassfromJava(path + File.separator + file[i], classes);
			}
		}
		return classes;
	}

	/**
	 * 这个方法利用了 StandardJavaFileManager类的优点。这个文件管理器提供了一种方法来完成普通文件的输入输出工作。 同时在一个
	 * DiagnosticListener实例的帮助下报告编译的诊断信息。后面将要用到的DiagnosticCollector类只是前面那个
	 * listener的一个实现。 在确定什么东西是需要编译的之前，你需要一个文件管理器。创建一个文件管理器需要两个基本的步骤：
	 * 创建一个DiagnosticCollector然后使用getStandardFileManager
	 * ()方法向JavaCompiler申请文件管理器。 传递
	 * DiagnosticListener实例作为getStandardFileManager()方法的参数。
	 * 这个listener报告非致命性的错误，你也可以选择通过将它传递给getTask()方法与编译器共享这个listener
	 */
	public static void compiler(String javafile) {
		if (!javafile.endsWith(".java")) {
			return;
		}
		try {
			JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
			if (compiler == null) {
				Log
						.log(
								"编译java代码出错,请检查如下内容:1.请检查代码是否书写正确.2.配置环境变量JAVA_HOME (或:手工将 %JDK_HOME%/lib/tools.jar 复制到 %JRE_HOME%/lib/下)",
								2);
			}
			// Log.log(compiler.toString(), 2);
			DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
			String charsetName = getChartsetName(javafile);

			StandardJavaFileManager fileManager = compiler
					.getStandardFileManager(diagnostics, null, Charset
							.forName(charsetName));
			
			// Log.log(fileManager.toString(), 2);
			Iterable<? extends JavaFileObject> compilationUnits = fileManager
					.getJavaFileObjectsFromStrings(Arrays.asList(javafile));
			// Log.log(compilationUnits.toString(), 2);
			
			ConfigXmlUtil util = new ConfigXmlUtil();
			Config config = util.getConfig();
			
			JavaCompiler.CompilationTask task = compiler.getTask(null,
					fileManager, diagnostics, Arrays.asList("-extdirs",config.getLibsDir()), null, compilationUnits);
			// Log.log(task.toString(), 2);
			
			Boolean success = task.call();
			// Log.log(success.toString(), 2);
			// for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
			// System.console().printf("Code: %s%n" + "Kind: %s%n" +
			// "Position: %s%n" + "Start Position: %s%n"
			// + "End Position: %s%n" + "Source: %s%n" + "Message:   %s%n",
			// diagnostic.getCode(), diagnostic.getKind(),
			// diagnostic.getPosition(),
			// diagnostic.getStartPosition(), diagnostic.getEndPosition(),
			// diagnostic.getSource(),
			// diagnostic.getMessage(null));
			// }
			Log.log("compile " + new File(javafile).getName()
					+ (success ? " success" : " fail"), 3);
			   for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
				   Log.log(String.valueOf(diagnostic),5);
			   }
			fileManager.close();
		} catch (IOException e) {
			Log.log(e);
		} catch (Exception e) {
			Log.log(e);
		}

	}

	/**
	 * 判断文件的编码格式
	 * 
	 * @param fileName
	 *            :file
	 * @return 文件编码格式
	 * @throws Exception
	 */
	/**
	 * 根据文件得到该文件中文本内容的编码
	 * 
	 * @param file
	 *            要分析的文件
	 **/
	public static String getChartsetName(String file) {
		String charset = ""; // 默认编码
		byte[] first3Bytes = new byte[3];
		BufferedInputStream bis = null;
		try {
			boolean checked = false;
			bis = new BufferedInputStream(new FileInputStream(file));
			bis.mark(0);
			int read = bis.read(first3Bytes, 0, 3);
			if (read == -1) {
				return null;
			}
			if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
				charset = "UTF-16LE";
				checked = true;
			} else if (first3Bytes[0] == (byte) 0xEF
					&& first3Bytes[1] == (byte) 0xBB
					&& first3Bytes[2] == (byte) 0xBF) {
				charset = "UTF-8";
				checked = true;
			}
			bis.reset();
			if (!checked) {
				charset = "GBK";
				int loc = 0;
				while ((read = bis.read()) != -1) {
					loc++;
					if (read >= 0xF0) {
						break;
					}
					// 单独出现BF以下的，也算是GBK
					if (0x80 <= read && read <= 0xBF) {
						break;
					}
					if (0xC0 <= read && read <= 0xDF) {
						read = bis.read();
						if (0x80 <= read && read <= 0xBF)// 双字节 (0xC0 - 0xDF)
							// (0x80 -0xBF),也可能在GB编码内
						{
							continue;
						} else {
							break;
						}
						// 也有可能出错，但是几率较小
					} else if (0xE0 <= read && read <= 0xEF) {
						read = bis.read();
						if (0x80 <= read && read <= 0xBF) {
							read = bis.read();
							if (0x80 <= read && read <= 0xBF) {
								charset = "UTF-8";
								break;
							} else {
								break;
							}
						} else {
							break;
						}
					}
				}
			}
			bis.close();
		} catch (Exception e) {
			Log.log(e);
			e.printStackTrace();
		} finally {
			if (bis != null) {
				try {
					bis.close();
				} catch (Exception e) {
					Log.log(e);
					e.printStackTrace();
				}
			}
		}
		Log.log(file + "文件字符编码:" + charset, 1);
		return "".equals(charset) ? null : charset;
	}

	public static String makeFilePath(String file) {
		file = filterDir(file);
		File files = new File(file);
		String dirPath = file.substring(0, files.getAbsolutePath().lastIndexOf(
				File.separator));
		File dirFile = new File(dirPath);

		if (!dirFile.exists()) {
			if (!dirFile.mkdirs()) {
				Log.log("创建文件失败", 2);
				throw new RuntimeException(dirFile + "文件夹创建失败");
			}
		}
		return file;
	}

	public static void mkdirs(String dirPath) {
		File dirFile = new File(dirPath);

		if (!dirFile.exists()) {
			if (!dirFile.mkdirs()) {
				Log.log("创建文件失败", 2);
				throw new RuntimeException(dirFile + "文件夹创建失败");
			}
		}
	}

}